/**
 * @file drv_eeprom.c
 * @brief Software implementation of eeprom for 51 microcontroller.
 * @author David Xu & zhongziming
 * @version 1.0.0
 * @date 2023-11-27
 * @note none
 */


#include "drv_eeprom.h"
#include "ct_sys.h"


static void EepromDelay(uint8_t milliseconds) {
    // HAL_Delay(milliseconds);
    ct_delay(milliseconds);
}


uint8_t EepromWrite(uint16_t memory_address, uint8_t *dat, uint16_t length) {
    uint8_t           chip_id;
    uint16_t          bytes_to_write;
    soft_i2c_buffer_t i2c_buffer;
    if (!dat) {
        return EEPROM_ERROR;    // Check for null pointer
    }
    // Check for address overflow or insufficient writable space
    if ((memory_address > EEPROM_MAX_ADDRESS) || ((memory_address + length) > EEPROM_MAX_ADDRESS)) {
        return EEPROM_ERROR;
    }

    // Loop until all data is transferred
    while (length) {
        chip_id = EEPROM_CHIP_ID;
        // Calculate how many bytes to write to fill up the current page
        bytes_to_write = EEPROM_PAGE_BYTES - (memory_address % EEPROM_PAGE_BYTES);
        if (bytes_to_write > length) { bytes_to_write = length; }

// Recalculate chip ID if using more register address bits (for 24C04/08/16)
#if EEPROM_MORE_REG_BITS
        chip_id = ((chip_id & (0xFF << (EEPROM_MORE_REG_BITS + 1))) | (memory_address >> 7)) & 0xFE;
#endif
        // Select I2C write function based on the number of bytes in the chip register
        // address
        i2c_buffer.buffer = dat;
        i2c_buffer.length = bytes_to_write;
#if EEPROM_REG_BYTES == 1
        ct_soft_i2c_Write_8Reg(&i2c_buffer, chip_id, memory_address);
#else
        ct_soft_i2c_Write_16Reg(&i2c_buffer, chip_id, memory_address);
#endif

        // Recalculate parameters for the next transfer
        dat += bytes_to_write;
        memory_address += bytes_to_write;
        length -= bytes_to_write;

        // Delay to wait for EEPROM chip to process data internally
        EepromDelay(EEPROM_WRITE_CYCLE_TIME);
    }

    return EEPROM_SUCCESS;
}

uint8_t EepromRead(uint16_t memory_address, uint8_t *dat, uint16_t length) {
    uint8_t           chip_id;
    soft_i2c_buffer_t i2c_buffer;
    if (!dat) {
        return EEPROM_ERROR;    // Check for null pointer
    }
    // Check for address overflow or insufficient readable space
    if ((memory_address > EEPROM_MAX_ADDRESS) || ((memory_address + length) > EEPROM_MAX_ADDRESS)) {
        return EEPROM_ERROR;
    }

    chip_id = EEPROM_CHIP_ID;
// Recalculate chip ID if using more register address bits (for 24C04/08/16)
#if EEPROM_MORE_REG_BITS
    chip_id = ((chip_id & (0xFF << (EEPROM_MORE_REG_BITS + 1))) | (memory_address >> 7)) & 0xFE;
#endif

    // Select I2C read function based on the number of bytes in the chip register address
    i2c_buffer.buffer = dat;
    i2c_buffer.length = length;
#if EEPROM_REG_BYTES == 1
    ct_soft_i2c_Read_8Reg(&i2c_buffer, chip_id, (uint8_t)memory_address);
#else
    ct_soft_i2c_Read_16Reg(&i2c_buffer, chip_id, memory_address);
#endif

    return EEPROM_SUCCESS;
}
